/**
 * Copyright (c) 2013, James Nutaro
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met: 
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution. 
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those
 * of the authors and should not be interpreted as representing official policies, 
 * either expressed or implied, of the FreeBSD Project.
 *
 * Bugs, comments, and questions can be sent to nutaro@gmail.com
 */
#ifndef __adevs_simpledigraph_h_
#define __adevs_simpledigraph_h_
#include "adevs.h"
#include <map>
#include <set>
#include <cstdlib>

namespace adevs
{

/**
 * This is a very simple digraph model for connecting single input/single
 * output systems. Output generated by a component model is sent to all
 * components connected to it.
 */
template <class VALUE, class T = double> class SimpleDigraph: 
public Network<VALUE,T>
{
	public:
		/// A component of the SimpleDigraph model
		typedef Devs<VALUE,T> Component;

		/// Construct a network without components.
		SimpleDigraph():
		Network<VALUE,T>()
		{
		}
		/// Add a model to the network.
		void add(Component* model);
		/// Couple the source model to the destination model.  
		void couple(Component* src, Component* dst);
		/// Puts the network's set of components into c
		void getComponents(Set<Component*>& c);
		/// Route an event according to the network's couplings
		void route(const VALUE& x, Component* model, 
		Bag<Event<VALUE,T> >& r);
		/// Destructor.  Destroys all of the component models.
		~SimpleDigraph();

	private:	
		// The set of components
		Set<Component*> models;
		// Coupling information
		std::map<Component*,Bag<Component*> > graph;
};

template <class VALUE, class T>
void SimpleDigraph<VALUE,T>::add(Component* model)
{
	assert(model != this);
	models.insert(model);
	model->setParent(this);
}

template <class VALUE, class T>
void SimpleDigraph<VALUE,T>::couple(Component* src, Component* dst) 
{
	if (src != this) add(src);
	if (dst != this) add(dst);
	graph[src].insert(dst);
}

template <class VALUE, class T>
void SimpleDigraph<VALUE,T>::getComponents(Set<Component*>& c)
{
	c = models;
}

template <class VALUE, class T>
void SimpleDigraph<VALUE,T>::
route(const VALUE& x, Component* model, 
Bag<Event<VALUE,T> >& r)
{
	// Find the list of target models and ports
	typename std::map<Component*,Bag<Component*> >::iterator graph_iter;
	graph_iter = graph.find(model);
	// If no target, just return
	if (graph_iter == graph.end()) return;
	// Otherwise, add the targets to the event bag
	Event<VALUE,T> event;
	typename Bag<Component*>::iterator node_iter;
	for (node_iter = (*graph_iter).second.begin();
	node_iter != (*graph_iter).second.end(); node_iter++)
	{
		event.model = *node_iter;
		event.value = x;
		r.insert(event);
	}
}

template <class VALUE, class T>
SimpleDigraph<VALUE,T>::~SimpleDigraph()
{ 
	typename Set<Component*>::iterator i;
	for (i = models.begin(); i != models.end(); i++)
	{
		delete *i;
	}
}

} // end of namespace 

#endif
